﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using LiniarAlgebra;
using PCA;
using SupervisedSpeakerRecognition.SVM;
using ZedGraph;


namespace SupervisedSpeakerRecognition
{
    class LogicLayerManager
    {
        private CepstralAnalysisManager _mfccManager = null;
        private Model _model;
        List<FileDetails> _wavFileDetails;
        public List<PointD> SVMpoints = new List<PointD>();

        public LogicLayerManager(List<FileDetails> wavFileDetails)
        {
            _wavFileDetails = wavFileDetails;
            // check all files in list are valid
            for (int i = 0; i < wavFileDetails.Count; i++)
                if (!File.Exists(wavFileDetails[i].FilePath))
                    throw new Exception(" File Name: " + wavFileDetails[i].FilePath + " dose not exist.");

        }

        public void useDefaultMFCCManagerParameters()
        {
            _mfccManager = new CepstralAnalysisManager();
            _mfccManager.WindowType = "Hamming";
            _mfccManager.Alpha = 0.95;
            _mfccManager.WinSize = 1024;
            String overlap = "50%";
            overlap = overlap.Substring(0, overlap.Length - 1);
            _mfccManager.OverLap = _mfccManager.WinSize * Int16.Parse(overlap) / 100;
            _mfccManager.UsingHamming = true;
            _mfccManager.UseStripSilence = false;
            _mfccManager.RealOnly = true;
            _mfccManager.UsingMelFilter = true;
            _mfccManager.PowMagnitude = false;
            _mfccManager.UseFirstCoeffAC = false;
            _mfccManager.GetHighFreq = false;
            _mfccManager.NumberOfMFCC = 16;
            _mfccManager.DistanceType = DistanceMeasurement.ManhattanDistance;
            // check if number of MFCC is less then winsize
            //TODO remove it to be check in the mfccmanager
            if (_mfccManager.WinSize <= _mfccManager.NumberOfMFCC)
                throw new Exception("Window size must be grater then number of MFCC");

        }
        public void initMFCCManager(String windowType, double alpha, int winSize, int overLap, bool hamming, bool stripSilence, bool realOnly,
            bool melFilter, bool powMagnitude, bool firstCoeffAC, bool highFreq, int numberOfMFCC)
        {
            _mfccManager = new CepstralAnalysisManager();
            _mfccManager.WindowType = windowType;
            _mfccManager.Alpha = alpha;
            _mfccManager.WinSize = winSize;
            _mfccManager.OverLap = _mfccManager.WinSize * overLap / 100;
            _mfccManager.UsingHamming = hamming;
            _mfccManager.UseStripSilence = stripSilence;
            _mfccManager.RealOnly = realOnly;
            _mfccManager.UsingMelFilter = melFilter;
            _mfccManager.PowMagnitude = powMagnitude;
            _mfccManager.UseFirstCoeffAC = firstCoeffAC;
            _mfccManager.GetHighFreq = highFreq;
            _mfccManager.NumberOfMFCC = numberOfMFCC;
            // check if number of MFCC is less then winsize
            //TODO remove it to be check in the mfccmanager
            if (_mfccManager.WinSize <= _mfccManager.NumberOfMFCC)
                throw new Exception("Window size must be grater then number of MFCC");
        }

        public List<FileDetails> buildSVMModle(ToolStripProgressBar progressBar, System.Windows.Forms.Label label_ProgressBar)
        {
            if (_mfccManager == null)
                throw new Exception("mfcc_manager is null");
            _mfccManager.InputFiles = new string[_wavFileDetails.Count];
            _mfccManager.InputFilesNamesOnly = new string[_wavFileDetails.Count];
            for (int i = 0; i < _wavFileDetails.Count; i++)
            {
                _mfccManager.InputFiles[i] = _wavFileDetails[i].FilePath;
                _mfccManager.InputFilesNamesOnly[i] = extractFileNameFromPath(_wavFileDetails[i].FilePath);
            }

            //initialize build process parameters
            progressBar.Value = 0;
            label_ProgressBar.Text = "Starting Configuration";
            label_ProgressBar.Update();

            //TODO - check if max size should be init
            _mfccManager.runCompleteProcess(progressBar, label_ProgressBar);
            for (int i = 0; i < _wavFileDetails.Count; i++)
                _mfccManager.SaveData[i].Group = _wavFileDetails[i].Group;
            //Send data to SVM
            Problem train = Problem.Read(_mfccManager.SaveData); // for model               

            // using SVM according how it should be used
            //First, read in the training data.


            //For this example (and indeed, many scenarios), the default
            //parameters will suffice.
            Parameter parameters = new Parameter();
            double C;
            double Gamma;
            //This will do a grid optimization to find the best parameters
            //and store them in C and Gamma, outputting the entire
            //search to params.txt.

            //C = 2;
            //cache_size = 40;
            //eps = 0.001;
            //degree = 0;
            //gamma = 0.5;
            //nu = 0.5;
            //p = 0.1;
            //svm_type = svm_parameter.C_SVC;
            //kernel_type = svm_parameter.LINEAR;
            label_ProgressBar.Text = "Start Building SVM Model....";
            label_ProgressBar.Update();
            ParameterSelection.Grid(train, parameters, "params.txt", out C, out Gamma);
            //parameters.C = C;
            //parameters.Gamma = Gamma;

            parameters.C = 2;
            parameters.Gamma = 0.5;
            parameters.Degree = 0;
            parameters.KernelType = KernelType.LINEAR;

            //Train the model using the optimal parameters.
            _model = Training.Train(train, parameters);
            //for (int i = 0; i < _model.SupportVectorCount; i++)
            //{

            //    PointD P = new PointD(_model.SupportVectors[i][0].Value, _model.SupportVectors[i][1].Value);
            //    SVMpoints.Add(P);


            //    //int adf = _model.SupportVectors[i].Length;
            //    ////double[,] rt = new double[1,adf];
            //    //double[][] rt = new double[1][];
            //    //rt[0] = new double[adf];
            //    //for (int j = 0; j < _model.SupportVectors[i].Length; j++)
            //    //{
            //    //    rt[0][j] = _model.SupportVectors[i][j].Value;
            //    //   // rt[0,j] = _model.SupportVectors[i][j].Value;
            //    //}
            //    ////SVMpoints.Add(converToPoint(rt));
            //}
            //saving all the data from the mfcc process in (x,y) format (using pca)             
            for (int i = 0; i < _mfccManager.SaveData.Length; i++)
                _wavFileDetails[i].Point = converToPoint(_mfccManager.SaveData[i].IfftData);
            //for (int i = 0; i < _mfccManager.SaveData.Length; i++)
            //    _wavFileDetails[i].Point = new Point(_mfccManager.SaveData[i].IfftDataOneDim[0], _mfccManager.SaveData[i].IfftDataOneDim[1]); //converToPoint(_mfccManager.SaveData[i].IfftData);

            label_ProgressBar.Text = "SVM Model Building Complete";
            label_ProgressBar.Update();
            return _wavFileDetails;
        }


        public FileDetails analyse(ToolStripProgressBar progressBar, System.Windows.Forms.Label label_ProgressBar, FileDetails fileToPredict)
        {
            if (_mfccManager == null)
                throw new Exception("mfcc_manager is null");
            _mfccManager.InputFiles = new string[1];
            _mfccManager.InputFiles[0] = fileToPredict.FilePath;
            _mfccManager.InputFilesNamesOnly = new string[1];
            _mfccManager.InputFilesNamesOnly[0] = extractFileNameFromPath(fileToPredict.FilePath);
            //initialize build process parameters
            progressBar.Value = 0;
            label_ProgressBar.Text = "Starting Configuration";
            label_ProgressBar.Visible = false;
            label_ProgressBar.Visible = true;
            //label_ProgressBar.Update();

            //TODO - check if max size should be init
            _mfccManager.runCompleteProcess(progressBar, label_ProgressBar);
            //Perform classification on the test data, putting the
            //results in results.txt.
            _mfccManager.SaveData[0].Group = fileToPredict.Group; //TODO check !!
            Problem test = Problem.Read(_mfccManager.SaveData); // for prediction           
            fileToPredict.Group = Prediction.Predict(test, "results.txt", _model, false).ToString();
            fileToPredict.Group = File.ReadAllLines("results.txt")[0];
            fileToPredict.Point = converToPoint(_mfccManager.SaveData[0].IfftData);
            return fileToPredict;
        }

        private Point converToPoint(double[][] ifftData)
        {
            DoubleMatrix matrix = new DoubleMatrix(ifftData.Length, ifftData[0].Length);
            for (int i = 0; i < ifftData.Length; i++)
            {
                for (int j = 0; j < ifftData[i].Length; j++)
                {
                    try
                    {
                        matrix[i, j] = ifftData[i][j];
                    }
                    catch (Exception e) { Console.WriteLine(e.Message); }
                }
            }
            PCAtransform pcatTransform = new PCAtransform(matrix);
            pcatTransform.Calculate();
            Point point = new Point();
            point.X = pcatTransform.EigenValues[0];
            point.Y = pcatTransform.EigenValues[1];
            return point;
        }

        private String extractFileNameFromPath(String path)
        {
            String[] parts = path.Split('\\');
            return parts[parts.Length - 1];
        }
    }
}
